#include "Components/ComponentDamage.h"
#include "Components/ComponentOnFire.h"
#include "Components/ComponentBody.h"

#include "Engine/MathUtils.hpp"
#include "Network/PackageManager.h"
#include "Network/Packages/ComponentHealthPackage.h"

#include "Subsystems/SubsystemAnimalEntities.h"
#include "GameSingleton.h"
#include "GameRegistry.hpp"

using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    void ComponentDamage::damage(float amount)
    {
        if(amount > 0.0f && hitpoints > 0.0f)
        {
            hitpoints = MathUtils::Max<float>(hitpoints - amount, 0.0f);
            GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<ComponentHealthPackage>(this));;
        }
    }

    void ComponentDamage::update(float dt)
    {
        if(hitpoints <= 0.0f)
        {
            GameSingleton::packageManager->addSendPackageToQueue(std::make_shared<ComponentHealthPackage>(this));
            GameSingleton::singletonPtr->getSingleton<SubsystemAnimalEntities>()->removeAnimalEntity(entity);
            return;
        }
        float num = MathUtils::Abs(componentBody->collisionVelocityChange.posY);
        if(num > fallResilience)
        {
            float amount = MathUtils::Sqr<float>(MathUtils::Max<float>(num - fallResilience, 0.0f)) / 15.0f;
            damage(amount);
        }
        Vector3 position;
        componentBody->getPosition(position);

        if(position.posY < 1.0f || position.posY > 276.0f)
        {
            damage(hitpoints);
        }
        ComponentOnFire *onFire = componentOnFire;
        if(onFire != nullptr && (onFire->fireDuration > 0.0f || onFire->touchesFire == true))
        {
            damage(dt / fireResilience);
        }
    }

    static const std::string componentName = "Damage";
    const std::string &ComponentDamage::getName() const
    {
        return componentName;
    }
    const std::string &ComponentDamage::GetName()
    {
        return componentName;
    }

    void ComponentDamage::load(const nlohmann::json &jsonData)
    {
        ComponentOnFire **componentOnFirePtr = GameSingleton::gameRegistry->try_get<ComponentOnFire*>(entity);
        if(componentOnFirePtr != nullptr)
        {
            componentOnFire = *componentOnFirePtr;
        }
        else
        {
            componentOnFire = nullptr;
        }
        componentBody = GameSingleton::gameRegistry->get<ComponentBody*>(entity);

        hitpoints = jsonData["Hitpoints"].get<float>();
        attackResilience = jsonData["AttackResilience"].get<float>();
        fallResilience = jsonData["FallResilience"].get<float>();
        fireResilience = jsonData["FireResilience"].get<float>();
    }

    void ComponentDamage::save(nlohmann::json &jsonData)
    {
        jsonData["Hitpoints"] = hitpoints;
    }

} // namespace PocketSurvival
